/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package servidor.auxiliar;


import servidor.tcp.ConexaoServer;
import servidor.gui.ServerInterface;
import common.*;
import java.sql.*;
import java.util.Enumeration;
import servidor.rmi.RMIservice;

/**
 *
 * @author A8
 */
public class GereServer {

    ServerInterface guiServer = null;
    ConexaoServer ligacao = null;
    Connection connect = null;
    int MAX = 20;
    Arquivo clientes = null;
    RMIservice servico = null;

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Construtor

    public GereServer() {
    }

    public Arquivo getClientes() {
        return clientes;
    }

    /*
     * ------------------------------------------------------------
     *      Metudos de alteracao de variaveis
     * ------------------------------------------------------------
     */

    public void setInterfaceServer(ServerInterface guiServer){
        this.guiServer = guiServer;
    }

    public void setConexaoServer(ConexaoServer ligacao){
        this.ligacao = ligacao;
    }

    public void setConection(Connection connect){
        this.connect = connect;
    }

    public void setClientes(Arquivo clientes) {
        this.clientes = clientes;
    }

    public void setServico(RMIservice servico) {
        this.servico = servico;
    }


    /*
     * ------------------------------------------------------------
     *      Metudos de Verificacao dos dados recebidos
     * ------------------------------------------------------------
     */


     //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Loggin
    
    public Menssagem doLoggin(Menssagem mensagem){

        OpLogin sms =(OpLogin) mensagem;

        String nick = sms.getEmissor();
        String pass=sms.getPassword();

        RespOut resp = null;
        int logged = 0;

        try {
            String nick_read = null;
            String pass_read = null;
            String sql = "SELECT * FROM cliente";
            Statement s = connect.createStatement();
            ResultSet result = s.executeQuery(sql);
            while (result.next()) {
                nick_read = result.getString("NICKNAME");
                pass_read = result.getString("PASSWORD");
                if (nick.equals(nick_read) && pass.equals(pass_read)) {
                    resp = new RespOut("[Server]", "login ok", nick);
                    logged = 1;
                    return resp;
                }
            }
            if (logged == 0){
                OpErro erro = new OpErro("[Server]", "[ERRO]", "Loggin invalido!\nVerifique os seus dados.", "Dados");
                //throw new WrongLog();
                return erro;
            }
        } catch (Exception ex) {
            System.out.println("[ERRO]SQL:"+ex.getMessage());
            OpErro erro = new OpErro("[Server]", "[ERRO]", ex.getMessage(), "SQL");
            return erro;
        }
        return resp;
    }


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Registo

    public Menssagem doRegister(Menssagem mensagem){

        OpRegister sms =(OpRegister) mensagem;
//
//        System.out.println("Mensagem recebida no registo:"+sms.getName());
//        System.out.println("Mensagem recebida no registo:"+sms.getPassword());
//        System.out.println("Mensagem recebida no registo:"+sms.getPlace());
//        System.out.println("Mensagem recebida no registo:"+sms.getEmissor());
        System.out.println("Mensagem recebida no registo:"+sms.getMail());

        RespOut resp = null;
        String nick = sms.getEmissor();
        int regist = 0;
        try {
            String nick_read = null;
            String sql;
            Statement s;

            //Ver se o cliente ja existe
            sql="select count(*) from mydb.cliente where NICKNAME='"+sms.getEmissor()+"'";
            s = connect.createStatement();
            ResultSet result = s.executeQuery(sql);
            /*while (*/result.next();/*) {*/
                nick_read = result.getString(1);
                System.out.println("Nick:"+nick_read);
                if(nick_read.contains("1")){
                    OpErro erro = new OpErro("[Server]", "[ERRO]", "O Nickname a registar ja esta em utilizacao.", "Dados");
                    regist = 1;     //tirar
                    return erro;
                }          
            //}
            //if(nick_read==null){        //tirar
                //Ver se o seu nome e correctamente preenchido
                System.out.println("O nick nao existe");
                if(regist==0){
                    String reg="[A-Z][a-z]+ [A-Z][a-z]+";
                    if (!sms.getName().matches(reg)){
                        regist = 1;
                        OpErro erro = new OpErro("[Server]", "[ERRO]", "Nome Invalido.\nPreencha correctamente os campos primeiro\n e ultimo nome.\nCom primeiro crater em mausculo.", "Dados");
                        return erro;
                    }
                    System.out.println("O nick esta ok");
                }

                //Verificar mail
                if(regist==0){
                    String mailreg="[\\w.]+@([\\w]+\\.)+[a-zA-Z]{2,3}";
                    if (!sms.getMail().matches(mailreg)){
                        System.out.println("O mail esta nao ok");
                        regist = 1;
                        OpErro erro = new OpErro("[Server]", "[ERRO]", "E-Mail invalido.\nVerifique a estrutura do mesmo.", "Dados");
                        return erro;
                    }
                    System.out.println("O mail esta ok");
                }

                if(regist==0){
                    if(sms.getPlace()==null){
                        regist = 1;
                        OpErro erro = new OpErro("[Server]", "[ERRO]", "Preencho co campo localisacao.", "Dados");
                        return erro;
                    }
                }
            //}

            //Se todas as condicoes forem satisfeitas entao insere
            if(regist==0){
                sql = "INSERT INTO cliente (NICKNAME, PASSWORD, NAME, MAIL, PLACE) VALUES('"+sms.getEmissor()+"', '"+sms.getPassword()+"', '"+sms.getName()+"', '"+sms.getMail()+"', '"+sms.getPlace()+"');";
                s = connect.createStatement();
                s.executeUpdate(sql);

                System.out.println("INSERIDO COM SUCESSO!");
                resp = new RespOut("[Server]", "register ok", nick);
            }
        } catch (SQLException ex) {
            System.out.println("[ERRO]SQL:"+ex.getMessage());
            OpErro erro = new OpErro("[Server]", "[ERRO]", ex.getMessage(), "SQL");
            return erro;
        }
        return resp;
    }


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Followers
    
    public Menssagem showFollowers(Menssagem mensagem){

        OpFollowers sms =(OpFollowers) mensagem;

        RespOut coiso_e_tal = null;
        try {
            String follower = null;
            String a_devolver = "Follower";

            System.out.println("Estou no op Followers");
            String sql = "select NICKNAME from mydb.following where FOLLOWING_NICK = '"+sms.getEmissor()+"'";
            Statement s = connect.createStatement();
            ResultSet result = s.executeQuery(sql);
            if(result!=null){
                while (result.next()) {
                    follower = result.getString("NICKNAME");
                    a_devolver = a_devolver+":"+follower;
                }
                coiso_e_tal = new RespOut("[Server]", a_devolver, sms.getEmissor());
            }
            else{
                OpErro erro = new OpErro("[Server]", "[ERRO]", "Followers Inexistentes.", "Dados");
                return erro;
            }

        } catch (SQLException ex) {
            System.out.println("[ERRO]SQL:"+ex.getMessage());
            OpErro erro = new OpErro("[Server]", "[ERRO]", ex.getMessage(), "SQL");
            return erro;
        }
        return coiso_e_tal;
    }


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Following

    public Menssagem showFollowing(Menssagem mensagem){

        OpFollowing sms =(OpFollowing) mensagem;

        RespOut coiso_e_tal = null;
        try {
            String following = null;
            String a_devolver = "Following";
            String sql = "select FOLLOWING_NICK from mydb.following where NICKNAME = '"+sms.getEmissor()+"'";
            Statement s = connect.createStatement();
            ResultSet result = s.executeQuery(sql);
            if(result!=null){
                while (result.next()) {
                following = result.getString("FOLLOWING_NICK");
                a_devolver = a_devolver+":"+following;
                }
                coiso_e_tal = new RespOut("[Server]", a_devolver, sms.getEmissor());
            }
            else{
                OpErro erro = new OpErro("[Server]", "[ERRO]", "Nao Segue ninguem.", "Dados");
                return erro;
            }
        } catch (SQLException ex) {
            System.out.println("[ERRO]SQL:"+ex.getMessage());
            OpErro erro = new OpErro("[Server]", "[ERRO]", ex.getMessage(), "SQL");
            return erro;
        }
        return coiso_e_tal;
    }


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Pesquisa

    public Menssagem showSearch(Menssagem mensagem){

        OpSearch sms =(OpSearch) mensagem;

        RespOut coiso_e_tal = null;
        int existentes = 0;
        try {
            String nick = null;
            String a_devolver = "Pesquisa";

            String sql = "SELECT NICKNAME FROM cliente where NICKNAME !='"+sms.getEmissor()+"'";
            Statement s = connect.createStatement();
            ResultSet result = s.executeQuery(sql);

            while (result.next()) {
                nick = result.getString("NICKNAME");
                if (nick.contains(sms.getSearch())) {
                    System.out.println("Neste:"+nick);
                    a_devolver = a_devolver+":"+nick;
                    existentes++;
                }
            }
            if(existentes>0){
                coiso_e_tal = new RespOut("[Server]", a_devolver, nick);
            }
            else{
                OpErro erro = new OpErro("[Server]", "[ERRO]", "O elemento a pesquisar nao consta da base de dados.", "Dados");
                return erro;
            }
            
        } catch (SQLException ex) {
            System.out.println("[ERRO]SQL:"+ex.getMessage());
            OpErro erro = new OpErro("[Server]", "[ERRO]", ex.getMessage(), "SQL");
            return erro;
        }
        return coiso_e_tal;
    }


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Adicionar a seguir

    public Menssagem doFollow(Menssagem mensagem){

        OpFollow sms =(OpFollow) mensagem;

        RespOut resp = null;
        try {
            String sql = "select count(*) from mydb.following where nickname = '"+sms.getEmissor()+"' and following_nick = '"+sms.getFollow()+"'";
            Statement s = connect.createStatement();
            ResultSet result = s.executeQuery(sql);
            result.next();
            if(result.getString(1).equals("0")){
                sql = "INSERT INTO following (NICKNAME, FOLLOWING_NICK) VALUES('"+sms.getEmissor()+"', '"+sms.getFollow()+"');";
                s = connect.createStatement();
                s.executeUpdate(sql);
                resp = new RespOut("[Server]", "Entrada adicionado com sucesso.", sms.getEmissor());
            }
            else{
                OpErro erro = new OpErro("[Server]", "[ERRO]", "O Follow que pretende adicionar ja faz parte da sua lista.", "Dados");
                return erro;
            }
        } catch (SQLException ex) {
            System.out.println("[ERRO]SQL:"+ex.getMessage());
            OpErro erro = new OpErro("[Server]", "[ERRO]", ex.getMessage(), "SQL");
            return erro;
        }
        return resp;
    }


        //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mandar Mensagem
    public Menssagem doTweet(Menssagem sms) {

        String envia = sms.getMenssagem().replaceFirst("Tweet:", "");
        RespOut resp = null;
        try {
            String sql = "INSERT INTO mydb.tweets (TWEET, DATA, NICKNAME) VALUES('" + envia + "', '" + sms.getTime() + "', '" + sms.getEmissor() + "');";
            Statement s = connect.createStatement();
            s.executeUpdate(sql);
            toFollers(sms);
            resp = new RespOut("[Server]", "Entrada adicionado com sucesso.", sms.getEmissor());
        } catch (SQLException ex) {
            System.out.println("[ERRO]SQL:" + ex.getMessage());
            OpErro erro = new OpErro("[Server]", "[ERRO]", ex.getMessage(), "SQL");
            return erro;
        }
        return resp;
    }

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mandar mensagem aos Follers


    public void toFollers(Menssagem sms) {

        Menssagem resposta = null;
        System.out.println("TWEET RECEBIDO:" + sms.getMenssagem());
        OpFollowers followers = new OpFollowers(sms.getEmissor(), "Followers");
        Menssagem verFollers = showFollowers(followers);
        String[] adicionaSms = verFollers.getMenssagem().split(":");
        int tam = adicionaSms.length;
        System.out.println("Tamanho: "+tam);
        if (tam > 1) {
            for (int i = 1; i <tam; i++) {
                DataCliente utilizador = getClientes().pesquisaCliente(adicionaSms[i]);
                System.out.println("Com utilizador!!!");
                if (utilizador != null) {
                    System.out.println("A seguir:" + utilizador.getNickname());
                    resposta = new Menssagem(utilizador.getNickname(), "Ver mensagens");
                    Menssagem temp_sms = seeTweets(resposta);
                    if(utilizador.getLigacao()!=null){
                        System.out.println("Encontrei foller rmi");
                        String resp=utilizador.mandaTweetFollerRMI(temp_sms);
                        //Remover utilizadores nao ligados
                        if(resp==null){
                            this.getClientes().desliga(utilizador);
                        }
                        //-------------------------------fim
                    }
                    if(utilizador.getOut()!=null){
                        System.out.println("Encontrei foller tcp");
                        ligacao.enviaSmsFollers(temp_sms, utilizador);
                    }
                }
            }
        }
    }


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Listar todas as mensagens

    public Menssagem seeTweets(Menssagem sms){

        RespOut resp = null;
        String tweet = "";
        String nickname="";
        String data="";
        int n=0;
        String mensagem = "Mensagens";
        try {
            String sql = "SELECT NICKNAME, DATA, TWEET FROM mydb.tweets WHERE (NICKNAME in (select FOLLOWING_NICK from mydb.following where NICKNAME = '"+sms.getEmissor()+"'))or (NICKNAME = '"+sms.getEmissor()+"') ORDER BY data DESC ";
            Statement s = connect.createStatement();
            ResultSet result = s.executeQuery(sql);

            if(result!=null){
                while (result.next()) {
                    nickname = result.getString("NICKNAME");
                    data = result.getString("DATA");
                    tweet = result.getString("TWEET");
                    if(n==MAX-1)
                        break;
                    mensagem = mensagem+"#"+nickname+"-"+data+"#"+tweet;
                    n++;
                }
                resp = new RespOut("[Server]", mensagem, sms.getEmissor());
            }
            else{
                OpErro erro = new OpErro("[Server]", "[ERRO]", "Não possui tweets disponiveis.\nVerifique tambem se segue outras pessoas.", "Dados");
                return erro;
            }
 
        } catch (SQLException ex) {
            System.out.println("[ERRO]SQL:"+ex.getMessage());
            OpErro erro = new OpErro("[Server]", "[ERRO]", ex.getMessage(), "SQL");
            return erro;
        }
        return resp;
    }


    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Listar apenas as minhas mensagens

    public Menssagem seeMyTweets(Menssagem sms){
        
        RespOut resp = null;
        String tweet = "";
        String data="";
        String nickname="";
        int n=0;
        String mensagem = "Minhas";
        try {
            String sql = "SELECT NICKNAME, DATA, TWEET FROM mydb.tweets WHERE NICKNAME = '"+sms.getEmissor()+"' ORDER BY data DESC ";
            Statement s = connect.createStatement();
            ResultSet result = s.executeQuery(sql);

            if(result!=null){
                while (result.next()) {
                    nickname = result.getString("NICKNAME");
                    data = result.getString("DATA");
                    tweet = result.getString("TWEET");
                    if(n==MAX-1)
                        break;
                    mensagem = mensagem+"#"+nickname+"-"+data+"#"+tweet;
                    n++;
                }
                resp = new RespOut("[Server]", mensagem, sms.getEmissor());
            }
            else{
                OpErro erro = new OpErro("[Server]", "[ERRO]", "Não possui tweets disponiveis.", "Dados");
                return erro;
            }


        } catch (SQLException ex) {
            System.out.println("[ERRO]SQL:"+ex.getMessage());
            OpErro erro = new OpErro("[Server]", "[ERRO]", ex.getMessage(), "SQL");
            return erro;
        }
        return resp;
    }

    

    //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Mostar nome a localizacao do user

    public Menssagem showDetails(Menssagem mensagem){

        OpDetails sms =(OpDetails) mensagem;
        
        RespOut coiso_e_tal = null;
        try {
            String nick = null;
            String name = null;
            String place = null;

            String a_devolver = "Detalhes";
            System.out.println("A mostrar:"+sms.getUsername());
            String sql = "SELECT NAME, PLACE FROM cliente where NICKNAME ='"+sms.getUsername()+"'";
            Statement s = connect.createStatement();
            ResultSet result = s.executeQuery(sql);

            if(result!=null){
                while (result.next()) {
                    name = result.getString("NAME");
                    place = result.getString("PLACE");
                    a_devolver = a_devolver+":"+name+":"+place;
                }
                coiso_e_tal = new RespOut("[Server]", a_devolver, nick);
            }
            else{
                OpErro erro = new OpErro("[Server]", "[ERRO]", "Detalhes nao definidos.", "Dados");
                return erro;
            }

        } catch (SQLException ex) {
            System.out.println("[ERRO]SQL:"+ex.getMessage());
            OpErro erro = new OpErro("[Server]", "[ERRO]", ex.getMessage(), "SQL");
            return erro;
        }
        return coiso_e_tal;
    }

    public void saiAplicacao(){
        try {
            ligacao.setEstado("Off");
            ligacao.getObjectInput().close();
            ligacao.getObjectOutput().close();
            ligacao.getTcp_client().close();         
        } catch (Exception ex) {//Null pointer exception
            System.out.println("[Erro]:Ao encerrar os canais de comunicacao.\n"+ex.getMessage());
        }
        //System.exit(0);
    }

    public DataCliente efectuaPing(){
        Enumeration<DataCliente> en = this.getClientes().getOnline().elements();
        while (en.hasMoreElements()) {
            DataCliente dataCliente = en.nextElement();
            if(dataCliente.getLigacao()!=null){
                return dataCliente;
            }
        }
        return null;
    }

    public Menssagem fazLoggout(Menssagem mensagem) {

        System.out.println("Estou no faz loggout!!!");

        RespOut logout = null;

        DataCliente cliente = this.getClientes().getOnline().get(mensagem.getEmissor());
        if(cliente!=null){
            if(cliente.fazCanalClose().equals("ok")){
                this.getClientes().getOnline().remove(mensagem.getEmissor());
                logout = new RespOut("[Server]", "Loggout ok", mensagem.getEmissor());
                return logout;
            }
            else{
                OpErro erro = new OpErro("[Server]", "[ERRO]", "As suas credenciais sao invalidas.", "Dados");
                return erro;
            }
        }
        OpErro erro = new OpErro("[Server]", "[ERRO]", "O cliente nao existe nos clientes ligados.", "Dados");
        return erro;
    }
}
